/*
 * An abstract server class
 * Written by YUE CHI
 */

import java.io.IOException;
import java.net.SocketException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

/**
 * An abstract class server can be extended in other server.
 * @author YUE CHI
 * @version 1.0
 */
public abstract class AbstractServer
{

  /**
   * The string that will cause us to terminate.
   */
  public static final String TERMINATION_STRING = "BYE";

  /**
   * The maximum length of a datagram packet.
   */
  public static final int MAX_PACKET_LENGTH = 65535;

  /**
   * The minimum valid port number.
   */
  public static final int MIN_PORT_NUMBER = 1024;

  /**
   * The maximum valid port number.
   */
  public static final int MAX_PORT_NUMBER = 65535;

  /**
   * The ASC CODE For US.
   */
  public static final String ASC_CODE = "US-ASCII";

  /**
   * The UDP data gram socket used by this UDPSpellingServer.
   */
  protected final int my_port;

  /**
   * The word list data gram contain in UDPServer.
   */
  protected final WordList my_word_list;

  /**
   * The constructor of server.
   * @param the_args the input string array.
   * @throws SocketException 
   */
  public AbstractServer(final String[] the_args) throws SocketException
  {
    this.my_port = getPort(the_args);
    this.my_word_list = getlist(the_args[1]);
  }

  /**
   * Get the port number.
   * @param the_args the input string
   * @return the port number
   */
  private int getPort(final String[] the_args)
  {
    int iport = 0;
    try
    {
      iport = Integer.parseInt(the_args[0]);
    }
    catch (final NumberFormatException e)
    {
      System.err.println("Port number must be numeric");
      System.exit(1);
    }
    if (iport < MIN_PORT_NUMBER || iport > MAX_PORT_NUMBER)
    {
      System.err.println("Port number must be between " + MIN_PORT_NUMBER + " and " +
                         MAX_PORT_NUMBER + " inclusive.");
      System.exit(1);
    }
    return iport;
  }

  /**
   * Get the wordlist from the local file.
   * 
   * @param the_args is the file name with location
   * @return a WordList type of listing word shown in the txt file
   */

  private WordList getlist(final String the_args)
  {
    WordList wlist = new WordList(new HashSet());
    try
    {
      Log.out("Loading wordlist......");
      wlist = new WordList(the_args);
      Log.out("Load wordlist succesfully :)");
    }
    catch (final IOException e)
    {
      Log.err("Load wordlist fail :(" + e);
      System.exit(1);
    }
    return wlist;
  }
  /**
   * Get the Datagram with the input of number and word.
   * @param the_i the number of word
   * @param the_s the word need to be check
   * @param the_thread    the thread number.
   * @return A Data type of stream. This datagram type shown in other class
   */
  protected Data getdata(final int the_i, final String the_s, final int the_thread)
  {
    final String prefix = the_thread + "-----";
    Log.out("Query word " + the_s);
    final Set tree_set = new TreeSet();
    if (my_word_list.isInList(the_s))
    {
      Log.out(prefix + "Word is spelled correctly.");
    }
    else
    {
      tree_set.addAll(my_word_list.getCloseWords(the_s));
      final Iterator iterator = tree_set.iterator();
      if (tree_set.size() == 0)
      {
        System.out.println(prefix + "No suggestion word");
      }
      else
      {
        System.out.println(prefix + 
           "Word is not spelled correctly, " + tree_set.size() + "suggestions:");
        while (iterator.hasNext())
        {
          System.out.print((String) iterator.next() + " ");
        }
      }
    }
    return new Data(the_i, the_s, my_word_list.isInList(the_s), tree_set);
  }
  

}
